{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `FileDownload` widget allows downloading a file on the frontend by sending the file data to the browser either on initialization (if `embed=True`) or when the button is clicked.\n",
    "\n",
    "Discover more on using widgets to add interactivity to your applications in the [how-to guides on interactivity](../../how_to/interactivity/index.md). Alternatively, learn [how to set up callbacks and (JS-)links between parameters](../../how_to/links/index.md) or [how to use them as part of declarative UIs with Param](../../how_to/param/index.md).\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
    "\n",
    "##### Core\n",
    "\n",
    "* **`auto`** (boolean):  Whether to download the file with the first click (if `True`) or only after clicking a second time (if `False`, enables right-click -> Save as).\n",
    "* **`callback`** (callable): A callable that returns a file or file-like object (takes precedence over `file` if set). \n",
    "* **`embed`** (boolean):  Whether to embed the data on initialization.\n",
    "* **`file`** (str, Path or file-like object):  A path to a file or a file-like object.\n",
    "* **`filename`** (str): The filename to save the file as.\n",
    "\n",
    "##### Display\n",
    "\n",
    "* **`button_style`** (str): The button style, either 'solid' or 'outline'.\n",
    "* **`button_type`** (str): A button theme; should be one of `'default'` (white), `'primary'` (blue), `'success'` (green), `'info'` (yellow), `'light'` (light), or `'danger'` (red)\n",
    "* **`icon`** (str): An icon to render to the left of the button label. Either an SVG or an icon name which is loaded from [tabler-icons.io](https://tabler-icons.io)/.\n",
    "* **`icon_size`** (str): Size of the icon as a string, e.g. 12px or 1em.\n",
    "* **`label`** (str): A custom label for the download button (by default uses the filename)\n",
    "* **`name`** (str): The title of the widget\n",
    "\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `FileDownload` widget accepts a path to a file or a file-like object (with a `.read` method) if the latter is provided a `filename` must also be set. By default (`auto=True` and `embed=False`) the file is only transferred to the browser after the button is clicked (this requires a live-server or notebook kernel):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "file_download = pn.widgets.FileDownload(file='FileDownload.ipynb', filename='custom_filename.ipynb')\n",
    "\n",
    "file_download"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The file data may also be embedded immediately using `embed` parameter, this allows using the widget even in a static export:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pn.widgets.FileDownload(file='FileDownload.ipynb', embed=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If `auto=False` is set the file will not be downloaded on the initial click but will change the label from \"Transfer <file>\" to \"Download <file>\" once the data has been synced. This offers an opportunity to download using the `Save as` dialog once the data has been transferred."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pn.widgets.FileDownload(\n",
    "    file='FileDownload.ipynb', button_type='success', auto=False,\n",
    "    embed=False, name=\"Right-click to download using 'Save as' dialog\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `FileDownload` widget may also be given a file-like object, e.g. here we save a pandas DataFrame as a CSV to a StringIO object and pass that to the widget:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from bokeh.sampledata.autompg import autompg\n",
    "\n",
    "from io import StringIO\n",
    "sio = StringIO()\n",
    "autompg.to_csv(sio)\n",
    "sio.seek(0)\n",
    "\n",
    "pn.widgets.FileDownload(sio, embed=True, filename='autompg.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you want to generate the file dynamically, e.g. because it depends on the parameters of some widget you can also supply a callback (which may be decorated with the widgets and/or parameters it depends on):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "years_options = list(autompg.yr.unique())\n",
    "years = pn.widgets.MultiChoice(\n",
    "    name='Years', options=years_options, value=[years_options[0]], margin=(0, 20, 0, 0)\n",
    ")\n",
    "mpg = pn.widgets.RangeSlider(\n",
    "    name='Mile per Gallon', start=autompg.mpg.min(), end=autompg.mpg.max()\n",
    ")\n",
    "\n",
    "def filtered_mpg(yrs, mpg):\n",
    "    df = autompg\n",
    "    if years.value:\n",
    "        df = autompg[autompg.yr.isin(yrs)]\n",
    "    return df[(df.mpg >= mpg[0]) & (df.mpg <= mpg[1])]\n",
    "\n",
    "def filtered_file(yr, mpg):\n",
    "    df = filtered_mpg(yr, mpg)\n",
    "    sio = StringIO()\n",
    "    df.to_csv(sio)\n",
    "    sio.seek(0)\n",
    "    return sio\n",
    "\n",
    "fd = pn.widgets.FileDownload(\n",
    "    callback=pn.bind(filtered_file, years, mpg), filename='filtered_autompg.csv'\n",
    ")\n",
    "\n",
    "pn.Column(\n",
    "    pn.Row(years, mpg),\n",
    "    fd,\n",
    "    pn.panel(pn.bind(filtered_mpg, years, mpg), width=600),\n",
    "    width=600\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Styles\n",
    "\n",
    "The color of the `FileDownload` button can be set by selecting one of the available `button_type` values and the `button_style` can be `'solid'` or `'outline'`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Row(\n",
    "    *(pn.Column(*(pn.widgets.FileDownload(button_type=p, button_style=bs) for p in pn.widgets.Button.param.button_type.objects))\n",
    "    for bs in pn.widgets.Button.param.button_style.objects)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Icons\n",
    "\n",
    "Like other buttons you can provide an explicit `icon`, either as a named icon loaded from [tabler-icons.io](https://tabler-icons.io)/:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Row(\n",
    "    pn.widgets.FileDownload(icon='alert-triangle-filled', button_type='warning', file='FileDownload.ipynb'),\n",
    "    pn.widgets.FileDownload(icon='bug', button_type='danger', file='FileDownload.ipynb')\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "or as an explicit SVG:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cash_icon = \"\"\"\n",
    "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"icon icon-tabler icon-tabler-cash\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" stroke-width=\"2\" stroke=\"currentColor\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n",
    "  <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\"/>\n",
    "  <path d=\"M7 9m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z\" />\n",
    "  <path d=\"M14 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0\" />\n",
    "  <path d=\"M17 9v-2a2 2 0 0 0 -2 -2h-10a2 2 0 0 0 -2 2v6a2 2 0 0 0 2 2h2\" />\n",
    "</svg>\n",
    "\"\"\"\n",
    "\n",
    "pn.widgets.FileDownload(icon=cash_icon, button_type='success', icon_size='2em', file='FileDownload.ipynb')"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
